<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>2018/12/3</title>
    <!--好的代码像粥一样,是得用时间和精力熬的。-->
</head>
<body>

<script>
    let s =Symbol();
    console.log(typeof s);  //symbol
    //原始的数据类型Symbol 表示独一无二的值，javascript里面的第六种数据类型
    //前六种：undefined null bollean string number object
   //Symbol函数可以接受一个字符串作为参数，表示对 Symbol 实例的描述，主要是为了在控制台显示，或者转为字符串时，比较容易区分。
    let s1= Symbol('foo');
    let s2= Symbol('bar');
    console.log(s1);
    console.log(s2);
    console.log(s1.toString());
    console.log(s2.toString());

    //如果 Symbol 的参数是一个对象，就会调用该对象的toString方法，将其转为字符串，然后才生成一个 Symbol 值。
    const obj = {
        toString(){
            return 'abc';
        }
    };
    const sym = Symbol(obj);
    console.log(sym);

    //Symbol函数的参数只是表示对当前 Symbol 值的描述，因此相同参数的Symbol函数的返回值是不相等的。
    //无参数
    let s5 = Symbol();
    let s6 = Symbol();
    console.log(s1 === s2);  // false
    //有参数
    let s3 = Symbol('foo');
    let s4 = Symbol('foo');
    console.log(s1 === s2);  // false

    //Symbol值不能与其他类型的值进行运算 ,会报错
    let sym1 = Symbol('my symbol');
    //console.log('yor symbol id' + sym1);
    //console.log(`your symbol is ${sym1}`);
    //Cannot convert a Symbol value to a string

    //Symbol 值可以显式转为字符串。
    let sym2 = Symbol('My symbol');
    console.log(String(sym2)); //Symbol(My symbol)
    console.log(sym2.toString());//Symbol(My symbol)

    //Symbol 值也可以转为布尔值，但是不能转为数值。
    let sym3 = Symbol();
    Boolean(sym3); //true
    console.log(!sym3); //false
    if(sym3){
        alert(11);
    }
    //Number(sym3);   //Cannot convert a Symbol value to a number
    //console.log(sym3 +2);     // Cannot convert a Symbol value to a number

    //由于每一个 Symbol 值都是不相等的，这意味着 Symbol 值可以作为标识符，用于对象的属性名，就能保证不会出现同名的属性。
    // 这对于一个对象由多个模块构成的情况非常有用，能防止某一个键被不小心改写或覆盖。
    let mySymbol = Symbol();
    //第一种写法
    let a1 = {};
    a1[mySymbol] = 'hello!';
    //第二种写法
    let a2= {
        [mySymbol]:'hello!',
    };
    //第三种写法
    let a3 = {};
    Object.defineProperty(a3,mySymbol,{value:'hello!'});
    //以上写法都得到同样结果
    console.log(a1[mySymbol]);//   'hello!'
    console.log(a2[mySymbol]);//   'hello!'
    console.log(a3[mySymbol]);//   'hello!'

    //Symbol 值作为对象属性名时，不能用点运算符。
    const mySymbol1 = Symbol();
    const a = {};

    a.mySymbol1 = 'Hello!';
    console.log(a[mySymbol1]); // undefined
    console.log(a['mySymbol1']); // "Hello!"

    //在对象的内部，使用 Symbol 值定义属性时，Symbol 值必须放在方括号之中。
    //如果s不放在方括号中，该属性的键名就是字符串s，而不是s所代表的那个 Symbol 值。
    // let s1 = Symbol();
    // let obj = {
    //     [s1]: function (arg) {...}
    // };
    // obj[s1](123);

    //采用增强的对象写法，上面代码的obj对象可以写得更简洁一些。
    // let obj = {
    //     [s1](arg) { ... }
    // };
    //Symbol 类型还可以用于定义一组常量，保证这组常量的值都是不相等的。
    const log = {};

    log.levels = {
        DEBUG: Symbol('debug'),
        INFO: Symbol('info'),
        WARN: Symbol('warn')
    };
    console.log(log.levels.DEBUG, 'debug message');
    console.log(log.levels.INFO, 'info message');



    const COLOR_RED    = Symbol();
    const COLOR_GREEN  = Symbol();
    function getComplement(color) {
        switch (color) {
            case COLOR_RED:
                return COLOR_GREEN;
            case COLOR_GREEN:
                return COLOR_RED;
            default:
                throw new Error('Undefined color');
        }
    }
    //Object.getOwnPropertySymbols方法返回一个数组，成员是当前对象的所有用作属性名的 Symbol 值。
    const obj1 = {};
    let x = Symbol('x');
    let y = Symbol('y');

    obj1[x] = 'Hello';
    obj1[y] = 'World';

    const objectSymbols = Object.getOwnPropertySymbols(obj1);

    console.log(objectSymbols);
    // [Symbol(x), Symbol(y)]

    //Object.getOwnPropertySymbols方法与for...in循环、Object.getOwnPropertyNames方法进行对比的例子。
    const obj2 = {};
    let foo = Symbol("foo");
    Object.defineProperty(obj2, foo, {
        value: "foobar",
    });
    for (let i in obj2) {
        console.log(i); // 无输出
    }
    Object.getOwnPropertyNames(obj2);
    // []
    Object.getOwnPropertySymbols(obj2)

    // [Symbol(foo)]

</script>

</body>
</html>
